parser grammar AnasintSAM;

options {
	tokenVocab = AnalexSAM;
	backtrack = true;
}

@header {
	import machine.*;
	import static machine.PrimitiveFunctions.*;
	import static machine.InstructionFunctions.*;
}

@members {
	int lineNumber = 0;
	Instructions inst = new Instructions();
}

code returns [Instructions res]
  : (line)* EOF
  	{
  		res = inst;
  	}
	;
	
line
	: (function 
	| instruction)
	{
		lineNumber++;
	}
	; 
 

function
	: tag=ID DOSPUNTOS instruction
	{
		inst.addFunction(tag.getText(), lineNumber);		
	}
	;

instruction
	: load
	| loada
	| loadi
	| loadl
	| store
	| storei
	| call_1
	| call_2
	| return_
 	| push
	| pop
	| jump
	| jumpi
	| jumpif
	| halt
	;
  
load
	: LOAD ABREPAR n=NUMERO CIERRAPAR d=NUMERO ABRECOR r=REGISTRO CIERRACOR
  	{  		
  		inst.add(new Instruction(
  			InstructionName.valueOf("LOAD"), 
  			RegMne.valueOf(r.getText()), 
  			Integer.parseInt(n.getText()), 
  			Integer.parseInt(d.getText())
  		));
  	}
  	;

loada  
	: LOADA n=NUMERO ABRECOR r=REGISTRO CIERRACOR
	{
	
		inst.add(new Instruction(
  			InstructionName.valueOf("LOADA"), 
  			RegMne.valueOf("SB"),
  			null,
  			Integer.parseInt(n.getText())
  		));		
	}
	;

loadi
	: LOADI ABREPAR n=NUMERO CIERRAPAR
	{
		inst.add(new Instruction(
			InstructionName.valueOf("LOADI"), 
			null,
			n.getText(), 
			null
		));
	}
	;
	
loadl
	: LOADL ABREPAR n1=NUMERO CIERRAPAR n2=NUMERO
	{
		inst.add(new Instruction(
			InstructionName.valueOf("LOADL"), 
			null,
			Integer.parseInt(n2.getText()),
			Integer.parseInt(n1.getText()) 
		));
	}
	;
	
store
	: STORE ABREPAR n=NUMERO CIERRAPAR d=NUMERO ABRECOR r=REGISTRO CIERRACOR
	{
		inst.add(new Instruction(
			InstructionName.valueOf("STORE"), 
			RegMne.valueOf(r.getText()), 
			Integer.parseInt(n.getText()), 
			Integer.parseInt(d.getText())			
		));
	}
	;
	
storei
	: STOREI ABREPAR n=NUMERO CIERRAPAR
	{
		inst.add(new Instruction(
			InstructionName.valueOf("STOREI"), 
			null,
			n.getText(), 
			null
		));
	}
	;

call_1
	: CALL ABREPAR n=NUMERO CIERRAPAR r=ID
	{
		inst.add(new Instruction(
			InstructionName.valueOf("CALL"), 
			RegMne.valueOf("PB"), 
			n.getText(), 
			Primitive.valueOf((r.getText()).toUpperCase())
		));
	}
	;
	
call_2 
	: CALL ABREPAR r1=REGISTRO CIERRAPAR r2=ID
	{
		inst.add(new Instruction(
			InstructionName.valueOf("CALL"), 
			RegMne.valueOf("CP"), 
			RegMne.valueOf(r1.getText()), 
			r2.getText()
		));
	}
	;
	
return_
	: RETURN ABREPAR n1=NUMERO CIERRAPAR n2=NUMERO
	{
		inst.add(new Instruction(
			InstructionName.valueOf("RETURN"),
			null, 
			n1.getText(),
			n2.getText()
		));
	}
	;
	
push
	: PUSH d=NUMERO
	{
		inst.add(new Instruction(
			InstructionName.valueOf("PUSH"),
			null,
			Integer.parseInt(d.getText()),			
			null
		));
	}
	;
       
pop
	: POP d=NUMERO
	{
		inst.add(new Instruction(
			InstructionName.valueOf("POP"),
			null,
			null,
			d.getText()
		));        
	}
	;
	
jump
	: JUMP d=NUMERO ABRECOR r=REGISTRO CIERRACOR
	{
		inst.add(new Instruction(
			InstructionName.valueOf("JUMP"), 
			RegMne.valueOf(r.getText()), 
			null,
			d.getText()
		));		
	}
	;
	
jumpi
	: JUMPI
	{
		inst.add(new Instruction(
			InstructionName.valueOf("JUMPI")
		));	
	}
	;
	
jumpif
	: JUMPIF ABREPAR n=NUMERO CIERRAPAR d=NUMERO ABRECOR r=REGISTRO CIERRACOR
	{
		inst.add(new Instruction(
			InstructionName.valueOf("JUMPIF")
		));	
	}
	;

halt
	: HALT
	{
		inst.add(new Instruction(
			InstructionName.valueOf("HALT")
		));
	}
	;